package com.example.calc20;

import java.util.Collections;
import java.util.Stack;



public class Calculator {
	private Stack<String> postfixStack = new Stack<String>();
	private Stack<Character> opStack = new Stack<Character>();
	private int[] operatPriority = new int[] { 0, 3, 2, 1, -1, 1, 0, 2 };

	public static double conversion(String expression) {
		double result = 0;
		Calculator cal = new Calculator();
		try {
			expression = transform(expression);
			result = cal.calculate(expression);
		} 
		catch (Exception e) {
			// e.printStackTrace();
			return 0.0 / 0.0;
		}
		return result;
	}


	private static String transform(String expression) {
		char[] arr = expression.toCharArray();
		for (int i = 0; i < arr.length; i++) {
			if (arr[i] == '-') {
				if (i == 0) {
					arr[i] = '~';
				} 
				else {
					char c = arr[i - 1];
					if (c == '+' || c == '-' || c == '*' || c == '/'
							|| c == '(' || c == 'E' || c == 'e') {
						arr[i] = '~';
					}
				}
			}
		}
		if (arr[0] == '~' || arr[1] == '(') {
			arr[0] = '-';
			return "0" + new String(arr);
		}
		else {
			return new String(arr);
		}
	}


	public double calculate(String expression) {
		Stack<String> resultStack = new Stack<String>();
		prepare(expression);
		Collections.reverse(postfixStack);
		String firstValue, secondValue, currentValue;
		while (!postfixStack.isEmpty()) {
			currentValue = postfixStack.pop();
			

			if (!isOperator(currentValue.charAt(0))) {
				currentValue = currentValue.replace("~", "-");
				resultStack.push(currentValue);
			} 

			else {
				secondValue = resultStack.pop();
				firstValue = resultStack.pop();


				firstValue = firstValue.replace("~", "-");
				secondValue = secondValue.replace("~", "-");

				String tempResult = calculate(firstValue, secondValue,
						currentValue.charAt(0));
				resultStack.push(tempResult);
			}
		}
		return Double.valueOf(resultStack.pop());
	}


	
	private void prepare(String expression) {
		opStack.push(',');
		char[] arr = expression.toCharArray();
		int currentIndex = 0;
		int count = 0;
		char currentOp, peekOp;
		for (int i = 0; i < arr.length; i++) {
			currentOp = arr[i];
			if (isOperator(currentOp)) {
				if (count > 0) {

					postfixStack.push(new String(arr, currentIndex, count));
				}
				peekOp = opStack.peek();
				

				if (currentOp == ')') {
					while (opStack.peek() != '(') {
						postfixStack.push(String.valueOf(opStack.pop()));
					}
					opStack.pop();
				} 
				else {
					while (currentOp != '(' && peekOp != ','
							&& compare(currentOp, peekOp)) {
						postfixStack.push(String.valueOf(opStack.pop()));
						peekOp = opStack.peek();
					}
					opStack.push(currentOp);
				}
				count = 0;
				currentIndex = i + 1;
			} else {
				count++;
			}
		}

		if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {
			postfixStack.push(new String(arr, currentIndex, count));
		}
		

		while (opStack.peek() != ',') {
			postfixStack.push(String.valueOf(opStack.pop()));
		}
	}


	private boolean isOperator(char c) {
		return c == '+' || c == '-' || c == '*' || c == '/' || c == '('|| c == ')';
	}


	public boolean compare(char cur, char peek) {
		boolean result = false;
		if (operatPriority[(peek) - 40] >= operatPriority[(cur) - 40]) {
			result = true;
		}
		return result;
	}


	private String calculate(String firstValue, String secondValue,
			char currentOp) {
		String result = "";
		switch (currentOp) {
		case '+':
			result = String.valueOf(com.example.calc20.HighPrecisionCalculator.add(firstValue, secondValue));
			break;
		case '-':
			result = String.valueOf(com.example.calc20.HighPrecisionCalculator.sub(firstValue, secondValue));
			break;
		case '*':
			result = String.valueOf(com.example.calc20.HighPrecisionCalculator.mul(firstValue, secondValue));
			break;
		case '/':
			result = String.valueOf(com.example.calc20.HighPrecisionCalculator.div(firstValue, secondValue));
			break;
		}
		return result;
	}
}